# -*- coding:utf-8 -*-

# @File     :api_v1
# @Author   :Yupeng
# @Date     :2018/10/27 20:26

from django.contrib.auth import login, logout
from django.core.exceptions import ValidationError
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.urls import reverse
from django.utils.translation import ugettext as _
from django.db.models import Q
# from oauth2_provider.decorators import protected_resource
from hte.error.handle import abort_on_error
from .auth import *

from hte.error.handle import HTEError, HTEException
from hte.utils.general import *
from .models.users import AccountAction
from .notify import send_verification_email, send_reset_password_email
# from oauth2_provider.views.gengtic import ProtectedResourceView
from hte.utils.middleware import GlobalRequestMiddleware


def _send_verification_email(user):
    token = user.generate_token(AccountAction.VERIFY_EMAIL)
    link = 'http://%s%s' % (
        GlobalRequestMiddleware.get_current_request().get_host(), reverse('accounts:verify_email') + '?token=' + token)
    send_verification_email(user, link)


@require_methods_api(["POST", "DELETE"])
def session_api(request: HttpRequest):
    """
    POST: 登录
        username: 用户名
        password: 密码
    DELETE: 注销
    """
    if request.method == "POST":
        username_or_email = get_json_field_r(request, 'user', str)
        password = get_json_field_r(request, 'password', str)
        # captcha_response = get_json_field_r(request, 'captcha_response', str).upper()
        # if 'captcha_response' in request.session:
        #     answer = request.session['captcha_response']
        #     del request.session['captcha_response']
        # else:
        #     answer = None
        # if answer is None or answer != captcha_response:
        #     abort_on_error(HTEError.WRONG_CAPTCHA)

        users = User.objects.filter(Q(username=username_or_email) | Q(email=username_or_email))
        if users:
            user = users[0]
            if user.check_password(password):
                if not request.user.is_authenticated:
                    login(request, user)
                    # LoginHistory.objects.create(user=user, ip=get_remote_ip())
                return json_response({'user': user.username, 'email': user.email})
            else:
                abort_on_error(HTEError.WRONG_PASSWORD, error_details=_('fadsfads'))
        else:
            abort_on_error(HTEError.USER_NOT_FOUND)
    else:
        ret_data = {}
        if request.user.is_authenticated:
            ret_data['username'] = request.user.username
            ret_data['email'] = request.user.email
        logout(request)
        return json_response(ret_data)

@require_methods_api(["POST"])
def session_api_auto(request: HttpRequest):
    """
    POST: 登录
        username: 用户名
        password: 密码
    """
    if request.method == "POST":
        # print(request.user)
        # print(request.user.username)
        username_or_email = request.POST.get('user')
        password = request.POST.get('password')

        users = User.objects.filter(Q(username=username_or_email) | Q(email=username_or_email))
        if users:
            user = users[0]
            if user.check_password(password):
                if not request.user.is_authenticated:
                    login(request, user)
                    # print(request.user)
                    # print(request.user.username)
                    # print(user)
                    # print(user.username)
                    # LoginHistory.objects.create(user=user, ip=get_remote_ip())
                return json_response({'user': user.username, 'email': user.email})
                # return json_response("Login Succeccfully!", status_code=201)
            else:
                abort_on_error(HTEError.WRONG_PASSWORD)
        else:
            abort_on_error(HTEError.USER_NOT_FOUND)

@require_GET_api
def generate_captcha(request: HttpRequest):
    from hte.utils.captcha import generate_challenge
    challenge = generate_challenge()
    request.session['captcha_response'] = challenge
    from hte.utils.captcha import captcha_image
    out = captcha_image(challenge)
    response = HttpResponse(content_type='image/png')
    response.write(out.read())
    response['Content-length'] = out.tell()
    return response


@require_methods_api(['GET', 'POST'])
def user_list(request: HttpRequest):
    '''
    GET:获取用户列表（需要至少用户管理员权限）
    POST:注册,以后最好是改成手机号注册
    :param request:
    :return:
    '''
    if request.method == 'POST':
        username = get_json_field_r(request, 'username', str)
        # print(username)
        password = get_json_field_r(request, 'password', str)
        real_name = get_json_field_r(request, 'real_name', str)
        email = get_json_field_r(request, 'email', str)
        institution = get_json_field_r(request, 'institution', str)
        register_ip = get_remote_ip()
        if User.objects.filter(username=username).exists():
            abort_on_error(HTEError.USER_ALREADY_EXISTS)
        if User.objects.filter(email=email).exists():
            abort_on_error(HTEError.EMAIL_ALREADY_EXISTS)
        try:
            user = User(username=username, password=password, real_name=real_name,
                        email=email, institution=institution, register_ip=register_ip)
            user.set_password(password)
            user.save()
            # _send_verification_email(user)
            return json_response()
        except HTEError as e:
            raise e
        except ValidationError as e:
            raise e
    elif request.method == 'GET':
        # check_user_role_api(UserRole.USER_ADMIN)
        query_set = {}
        email = get_param('email')
        real_name = get_param('real_name')
        institution = get_param('institution')
        page = get_param('page', convert_to=int)
        if email:
            query_set['email'] = email
        if real_name:
            query_set['real_name'] = real_name
        if institution:
            query_set['institution'] = institution
        users = User.objects.filter(**query_set)
        if page:
            paginator = Paginator(users, 3)
            try:
                users = paginator.page(page)
            except EmptyPage:
                users = paginator.page(paginator.num_pages)
        return json_response(items=list(map(lambda x: x.to_dict(), users)))


@require_POST_api
@login_required_api
def resend_verification_email(request: HttpRequest):
    if request.user.email_verified:
        abort_on_error(HTEError.EMAIL_ALREADY_VERIFIED)
    _send_verification_email(request.user)
    s = _("An email has been sent to %(object1)s. Please click the link in it to verify your email address.")
    return json_response(s % {'object1': request.user.email})


@require_methods_api(["POST"])
def reset_password_request(request: HttpRequest):  # /users/password/reset_request
    '''
    忘记密码，填写邮箱后会往邮箱发送一个连接，包含token
    :param request:
    :return:
    '''
    try:
        user = User.objects.get(email=get_json_field_r(request, 'email', str))
        token = user.generate_token(AccountAction.RESET_PASSWORD)
        link = 'http://%s%s' % (
            request.get_host(),
            reverse('accounts:reset_password') + '?token=' + token)
        s = _("An email has been sent to %(object1)s. Please click the link in it to reset your password")
        send_reset_password_email(user, link)
        return json_response(s % {'object1': user.email})
    except User.DoesNotExist:
        abort_on_error(HTEError.USER_NOT_FOUND)


@require_PATCH_api
def reset_password(request: HttpRequest):
    '''
    忘记密码，从邮箱点击链接之后，在新的页面修改密码的操作
    :param request:
    :return:
    '''
    token = get_json_field_r(request, 'token', str)  # token
    new_password = get_json_field_r(request, 'new_password', str)
    user = User.user_from_token(token)
    if not user or not user.verify_token(token, AccountAction.RESET_PASSWORD):
        abort_on_error(HTEError.BAD_TOKEN)
    user.set_password(new_password)
    user.save()
    return json_response(_('Your password has been reset.'))


# @login_required_api
@require_methods_api(["GET", "PATCH", "DELETE"])
def user_resource(request: HttpRequest, username: str):
    '''
    #不能做登录要求，因为管理员应该可以查看普通用户的信息
    其实我感觉应该是分开来写，普通用户需要登陆才能看自己的信息
    :param request:
    :param username:这个参数是为了管理员能够获取其他用户的信息而设置的
    :return:
    '''



    try:
        user = User.objects.get(username=username)
    except User.DoesNotExist:
        return abort_on_error(HTEError.RESOURCE_NOT_FOUND)
    if request.method == "GET":
        if is_the_same_user(username) or check_user_role_api(user_role=UserRole.USER_ADMIN):
            # 以上第一个判断条件同时检测了用户是否登录
            return json_response(user.to_dict())
    elif request.method == "PATCH":
        if is_the_same_user(user):  # 用户自己更新个人信息
            """
                修改email
            """
            email = get_json_field_r(request, 'email', str)
            # 这里指明了需要修改信息，邮箱是必须的
            if email and user.email != email:
                if User.objects.filter(email=email).count() > 0:
                    abort_on_error(HTEError.EMAIL_ALREADY_EXISTS)
                old_status = user.email_verified
                old_email = user.email
                user.email = email
                user.email_verified = False
                try:
                    _send_verification_email(user)
                    user.save()
                    return json_response()
                except HTEException:

                    user.email = old_email
                    user.email_verified = old_status
                    user.save()
                    raise
            """
            修改密码及其他信息
            """
            new_password = get_json_field_r(request, 'new_password', str, allow_none=True)
            if new_password:
                old_password = get_json_field_r(request, 'old_password', str)
                if user.check_password(old_password):
                    user.set_password(new_password)
                else:
                    abort_on_error(HTEError.WRONG_PASSWORD)

            institution = get_json_field_r(request, 'institution', str, allow_none=True)
            real_name = get_json_field_r(request, 'real_name', str, allow_none=True)
            # sex = get_json_field('sex', str, allow_none=True, allowed=["M", "F"])
            if institution:
                user.institution = institution
            if real_name:
                user.real_name = real_name
            # if sex:
            # user.sex = sex

            user.save()
            return json_response()

        else:
            """
            管理员审核用户
            """
            check_user_role_api(UserRole.USER_ADMIN)
            if user.role == UserRole.VERIFIED_USER:
                abort_on_error(HTEError.PERMISSION_DENIED)
            verified = get_json_field_r('verified', bool)
            if verified:
                user.role = UserRole.VERIFIED_USER
                user.save()
            else:
                # TODO 给用户发送审核失败的通知？
                pass
            return json_response()

    if request.method == "DELETE":
        # TODO 添加删除用户功能
        return json_response()


@require_methods_api(["GET", "POST"])
def user_avatar(request: HttpRequest, username: str):
    if request.method == "POST":
        ensure_privacy(username)
        avatar = request.FILES.get('avatar')
        if avatar is None:
            abort_on_error(HTEError.FIELD_MISSING)
        else:
            request.user.set_avatar(avatar.file)
            return json_response()
    else:
        size = get_param('size', allowed=['large', 'small', 'normal'], allow_none=True)
        try:
            user = User.objects.get(username=username)
            a = user.get_avatar(size=size)
            if a is None:
                # 返回默认头像
                if isinstance(size, str):
                    size = size.lower()
                if size == User.AvatarSize.LARGE or size == 'large':
                    suffix = 'lg'
                elif size == User.AvatarSize.NORMAL or size == 'normal':
                    suffix = 'nm'
                else:
                    suffix = 'sm'
                filename = '%s_%s.jpg' % (settings.AVATAR_DIR + "/default", suffix)
                a = open(filename, 'rb').read()
            return HttpResponse(a, content_type='image/jpeg')
        except User.DoesNotExist:
            abort_on_error(HTEError.RESOURCE_NOT_FOUND)

# @require_methods_api(["GET", "PATCH", "DELETE"])
# def user_resource_admin(request:HttpRequest, username:int):
#     pass
